let { EventEmitter } = require('events');
import { _mapValues as mapValues } from './lodash'
import { memoizePromise, time, isEffective } from './utils'
import isValidToken from './checkToken';
import login from './login';
import uploadUserInfo from './uploadUserInfo'
import getRedirectUrl from './getRedirectUrl'
import createStorageState from './createState'
let wxappUserStoreKey = 'duiba-wxapp-user';
const userEventEmitter = new EventEmitter();

const params = {
  userLoginType: 0, // 0新用户 暂未上传过用户信息，1老用户 已上传过用户信息
  mobilePhone: '',
  nickName: '',
  avatar: '',
  gender: 0,
  autoLoginUrl: '',
  token: '',
  loginAt: 0,
}
const autoKeys = ['userLoginType', 'mobilePhone', 'nickName', 'avatar', 'gender', 'autoLoginUrl', 'token', 'loginAt']
let state = createStorageState(wxappUserStoreKey, params, autoKeys)

const mutations = {
  updateUserInfo(userInfo) {
    userInfo = {
      ...state,
      ...userInfo,
    };

    state.nickName = userInfo.nickName || '';
    state.avatar = userInfo.avatar || '';
    state.gender = +userInfo.gender || 0;
    state.mobilePhone = userInfo.mobilePhone || '';

    userEventEmitter.emit('afterUpdateUserInfo');
  },
  updateRedirectUrl(url) {
    state.autoLoginUrl = url;

    userEventEmitter.emit('afterUpdateRedirectUrl');
  },
  updateUserLoginType(userLoginType) {
    state.userLoginType = userLoginType;
    userEventEmitter.emit('afterUpdateUserLoginType');
  },
  loginSuccess(data) {
    console.log('==loginSuccess==', data)
    let newData = {
      ...state,
      ...data,
    }
    const { unionId, token, userLoginType, ...rest } = newData;
    Object.assign(state, {
      unionId,
      token,
      loginAt: time(), // 设置刷新时间（只是从storage中取则表示续期意思）
    })

    // 更新userLogin
    mutations.updateUserLoginType(userLoginType || 0);

    // 更新url 取最新返回的
    // mutations.updateRedirectUrl(data.autoLoginUrl || data.url || '');

    mutations.updateUserInfo(Object.assign({
      mobilePhone: '',
      nickName: '',
      avatar: '',
      gender: 0,
    }, rest))

    userEventEmitter.emit('loginSuccess')
  },
  loginError(err) {
    userEventEmitter.emit('loginError', err);
  },
}

const wxappUser = {
  emitter: userEventEmitter,
  envType: 'publish',
  /**
   * 保持登录状态 并返回用户信息
   * 先校验上次的登录态是否过期 若过期自动登录，否则不需要再次登录
   */
  keepLogin: memoizePromise(async (options = {}) => {
    console.log('==wxappUser.keepLogin==', options)
    try {
      await isValidToken(wxappUser.token, {
        ...wxappUser.defaults.options,
        ...options
      })

      return wxappUser;
    } catch(err) {
      console.error(err.message)
      await wxappUser.login({
        ...options,
        force: true
      });
    }
  }),

  /**
   * 登录
   * @param {*} options force=true为强制登录
   * @returns data
   */
  async login(options = {}) {
    console.log('==wxappUser.login==')
    try {
      const { userLogin, ...rest } = await login({
        ...wxappUser.defaults.options,
        ...options,
      }, state);

      // 2.a 登录成功，设置登录信息
      mutations.loginSuccess({
        userLoginType: userLogin,
        ...rest
      });
      return wxappUser;
    } catch(err) {
      mutations.loginError(err);
      throw err;
    }
  },
  /**
   * 上传用户信息
   * @param {*} uploadInfo 上传信息 
   * @param {*} options 额外参数 
   * @param {*} retryLimit 失败之后重新请求次数
   * @returns data
   */
  async loginWithUserInfo(uploadInfo, options, retryLimit = 2) {
    try {
      if (!wxappUser.token) {
        await wxappUser.login(options);
      }

      console.log('==调用上传用户信息接口--uploadUserInfo')
      const data = await uploadUserInfo({
        ...wxappUser.defaults.options,
        ...options
      }, uploadInfo, wxappUser.token)

      // 2.a 登录成功，设置登录信息
      mutations.loginSuccess({
        ...data,
        // 先设置为老用户，如果没有访问带头像昵称的免登地址已存储到数据库，后面会再次更新会新用户
        userLoginType: 1
      });
      // i：上传用户信息之后会返回带昵称头像的免登地址
      // a：自动访问免登地址，此时用户信息会被保存到数据库，用户状态为老用户
      // b：没有访问免登地址，getRedirectUrl获取免登地址之后会更新用户状态为新用户

      return data;
    } catch (err) {
      if (retryLimit > 0) {
        await wxappUser.login({
          ...options,
          force: true,
        });
        return wxappUser.loginWithUserInfo(uploadInfo, options, retryLimit - 1);
      }
      mutations.loginError(err);
      throw err;
    }
  },
  /**
   * 获取免登地址
   * @param {*} redirect 落地页地址
   */
  async getRedirectUrl({ redirect, ...rest }){
    try {
      if (!wxappUser.token) {
        await wxappUser.login(options);
      }
      console.log('getRedirectUrl==')
      let data = await getRedirectUrl(wxappUser.token, {
        ...wxappUser.defaults.options,
        ...rest,
        redirectUrl: redirect
      });
      // 更新当前用户的状态
      mutations.updateUserLoginType(data.userLogin);
      return data;
    } catch (error) {
      throw error;
    }
  },

  /**
   * 更新用户信息
   * @param {Object} userInfo
   */
  updateUserInfo(userInfo = {}) {
    mutations.updateUserInfo(userInfo);
  },
  /**
   * 设置登录类型
   * @param {Number} userLoginType
   */
  setUserLoginType(userLoginType = 0) {
    mutations.updateUserLoginType(userLoginType);
  },
  /**
   * 设置当前环境类型【当小程序中既存在测试环境又存在正式环境时 才需要特殊设置】
   * （一般情况下用不到，目前只是在兑吧测试小程序中用到）
   * @param {string} env
   */
  initEnvType(env) {
    wxappUser.envType = env;
    let envKey = `${wxappUserStoreKey}_${env}`
    state = createStorageState(envKey, state, autoKeys);
  },

  defaults: {
    options: {
      APP_KEY: '',
      API_BASE_URL: '',
      LOGIN_API: '',
      HEADERS_CONFIG: {}
    }
  }
}


Object.defineProperties(wxappUser, mapValues(state, (vo, key) => ({
  enumerable: true,
  configurable: false,
  get() {
      return state[key];
  }
})));

export default wxappUser;
